using System;
using System.Collections;
using System.Collections.Generic;

namespace LightCAD.Three
{
    public class PointLightShadow : LightShadow
    {
        #region scope properties or methods
        //private static Matrix4 _projScreenMatrix = new Matrix4();
        //private static Vector3 _lightPositionWorld = new Vector3();
        //private static Vector3 _lookTarget = new Vector3();
        private static PointLightShadowContext getContext()
        {
            return ThreadContext.getCurrThreadContext().PointLightShadowCtx;
        }
        #endregion

        #region Properties

        public JsArr<Vector3> _cubeDirections;
        public JsArr<Vector3> _cubeUps;

        #endregion

        #region constructor
        public PointLightShadow()
            : base(new PerspectiveCamera(90, 1, 0.5, 500))
        {
            this._frameExtents = new Vector2(4, 2);
            this._viewportCount = 6;
            this._viewports = new JsArr<Vector4>() { 
                    // These viewports map a cube-map onto a 2D texture with the
                    // following orientation:
                    //
                    //  xzXZ
                    //   y Y
                    //
                    // X - Positive x direction
                    // x - Negative x direction
                    // Y - Positive y direction
                    // y - Negative y direction
                    // Z - Positive z direction
                    // z - Negative z direction
                    // positive X
                    new Vector4(2, 1, 1, 1),
                    // negative X
                    new Vector4(0, 1, 1, 1),
                    // positive Z
                    new Vector4(3, 1, 1, 1),
                    // negative Z
                    new Vector4(1, 1, 1, 1),
                    // positive Y
                    new Vector4(3, 0, 1, 1),
                    // negative Y
                    new Vector4(1, 0, 1, 1)
                };
            this._cubeDirections = new JsArr<Vector3>() {
                    new Vector3(1, 0, 0), new Vector3(-1, 0, 0), new Vector3(0, 0, 1),
                    new Vector3(0, 0, -1), new Vector3(0, 1, 0), new Vector3(0, -1, 0)
                };
            this._cubeUps = new JsArr<Vector3>() {
                    new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0),
                    new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(0, 0, -1)
                };
        }
        #endregion

        #region methods
        public override void updateMatrices(Light light, int viewportIndex = 0)
        {
            var pointLight = light as PointLight;
            var camera = (PerspectiveCamera)this.camera;
            var shadowMatrix = this.matrix;
            var distance = pointLight.distance;
            var far = distance == 0 ? camera.far : distance;
            if (far != camera.far)
            {
                camera.far = far;
                camera.updateProjectionMatrix();
            }
            var ctx = getContext();
            var _lightPositionWorld = ctx._lightPositionWorld;
            var _lookTarget = ctx._lookTarget;
            var _projScreenMatrix = ctx._projScreenMatrix;
            _lightPositionWorld.setFromMatrixPosition(pointLight.matrixWorld);
            camera.position.copy(_lightPositionWorld);
            _lookTarget.copy(camera.position);
            _lookTarget.add(this._cubeDirections[viewportIndex]);
            camera.up.copy(this._cubeUps[viewportIndex]);
            camera.lookAt(_lookTarget);
            camera.updateMatrixWorld();
            shadowMatrix.makeTranslation(-_lightPositionWorld.x, -_lightPositionWorld.y, -_lightPositionWorld.z);
            _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
            this._frustum.setFromProjectionMatrix(_projScreenMatrix);
        }

        public override LightShadow clone()
        {
            var newShadow = new PointLightShadow();
            newShadow.copy(this);
            return newShadow;
        }
        #endregion

    }
}
